天天看點

uboot移植之uboot中的SD卡驅動解析

1:位址對硬體操作的影響

    (1)作業系統(指的是linux)下MMU肯定是開啟的,也就是說linux驅動中肯定都使用的是虛拟位址。而純裸機程式中根本不會開MMU,全部使用的是實體位址。這是裸機下和驅動中操控硬體的一個重要差別。

    (2)uboot早期也是純實體位址工作的,但是現在的uboot開啟了MMU做了虛拟位址映射,這個東西驅動也必須考慮。查uboot中的虛拟位址映射表,發現210開發闆裡面,除了0x30000000-0x3FFFFFFF映射到了0xC0000000-0xCFFFFFFF之外,其餘的虛拟位址空間全是原樣映射的。而我們驅動中主要是操控硬體寄存器,而S5PV210的SFR都在0xExxxxxx位址空間,是以驅動中不必考慮虛拟位址。

2:從start_armboot開始

這裡的();就是SD卡的初始化函數,這個函數的作用就是初始化開發闆上MMC系統。MMC系統的初始化應該包含這麼幾部分:SoC裡的MMC控制器初始化

(MMC系統時鐘的初始化、SFR初始化)、SoC裡MMC相關的GPIO的初始化、SD卡/iNand晶片的初始化。

3:mmc_initialize()函數分析

<code>int</code> <code>mmc_initialize(bd_t *bis)</code>

<code>{</code>

<code>struct</code> <code>mmc *mmc;</code>

<code>int</code> <code>err;</code>

<code>INIT_LIST_HEAD(&amp;mmc_devices);    </code><code>//初始化核心連結清單,next指針和prev指針都指向自身</code>

<code>cur_dev_num = 0;</code><code>// SD 卡的插槽,我們這裡有4個插槽</code>

<code>if</code> <code>(board_mmc_init(bis) &lt; 0)</code>

<code>cpu_mmc_init(bis);   </code><code>//時鐘初始化  GPIO初始化,但是目前都是初始化SoC内部,并沒有</code>

<code>              </code><code>//涉及外部的SD卡的初始化</code>

<code>#if defined(DEBUG_S3C_HSMMC)</code>

<code>print_mmc_devices(</code><code>','</code><code>);</code>

<code>#endif</code>

<code>#ifdef CONFIG_CHECK_X210CV3</code>

<code>mmc = find_mmc_device(1);</code><code>//lqm</code>

<code>#else</code>

<code>mmc = find_mmc_device(0);</code>

<code>if</code> <code>(mmc) {</code>

<code>err = mmc_init(mmc);</code>

<code>if</code> <code>(err)</code>

<code>if</code> <code>(err) {</code>

<code>printf</code><code>(</code><code>"Card init fail!\n"</code><code>);</code>

<code>return</code> <code>err;</code>

<code>}</code>

<code>printf</code><code>(</code><code>"%ldMB\n"</code><code>, (mmc-&gt;capacity/(1024*1024/(1&lt;&lt;9))));</code>

<code>return</code> <code>0;</code>

    (1)INIT_LIST_HEAD(&amp;mmc_devices);

核心連結清單的初始化函數,核心連結清單在初始化的時候,連結清單的next指針和prev指針都是指向其自身。mmc_devices連結清單全局變量,用來記錄系統中所有已經注冊的SD/iNand裝置。是以向系統中插入一個SD卡/iNand裝置,則系統驅動就會向mmc_devices連結清單中插入一個資料結構表示這個裝置。

    (2)if (board_mmc_init(bis) &lt; 0)

檢視代碼可知,board_mmc_init(),其實是__def_mmc_init()函數的别名,而__def_mmc_init()函數的傳回值固定是-1,是以if判斷成立,執行cpu_mmc_init()函數。

    (3)cpu_mmc_init()函數

cpu_mmc_init()函數在uboot/cpu/s5pc11x/cpu.c中,

int cpu_mmc_init(bd_t *bis)

{

#ifdef CONFIG_S3C_HSMMC

setup_hsmmc_clock();

setup_hsmmc_cfg_gpio();

return smdk_s3c_hsmmc_init();

#else

return 0;

#endif

}

setup_hsmmc_clock():在uboot/cpu/s5pc11x/setup_hsmmc.c中。hsmmc高速mmc,clock時鐘,是以這個函數應該是用于mmc控制器的時鐘初始化。裡面是通過宏定義來選擇配置哪些通道的時鐘(通過MPLL分頻得到)。x210選擇的是通道0和通道2(SD卡)

setup_hsmmc_cfg_gpio():MMC控制器IO引腳的設定。在在uboot/cpu/s5pc11x/setup_hsmmc.c中中

smdk_s3c_hsmmc_init():uboot/drivers/mmc/s3c_hsmmc.c中。該函數裡面主要調用s3c_hsmmc_initialize(int channel)函數,參數channel表示的是MMC的通道。

至此,cpu_mmc_init()函數分析結束,繼續分析mmc_initialize()函數。

    (4) find_mmc_device(0)函數

find_mmc_device()uboot/drivers/mmc/mmc.c中,這個函數其實就是通過mmc裝置編号來在系統中查找對應的mmc裝置(struct mmc的對象,根據上面分析系統中有2個,編号分别是0和2)。函數工作原理就是通過周遊mmc_devices連結清單,去依次尋找系統中注冊的mmc裝置,然後對比其裝置編号和我們目前要查找的裝置編号,如果相同則就找到了要找的裝置。找到了後調用mmc_init函數來初始化它。

    (5)mmc_init()函數

mmc_init()函數在drivers/mmc/mmc.c中。這個函數的主要作用是進行mmc卡的初始化。mmc_init函數内部就是依次通過向mmc卡發送指令碼(CMD0、CMD2那些)來初始化SD卡/iNand内部的控制器,以達到初始化SD卡的目的。

4:總結

    (1)整個MMC系統初始化分為2大部分:SoC這一端的MMC控制器的初始化,SD卡這一端卡本身的初始化。前一步主要是在cpu_mmc_init函數中完成,後一部分主要是在mmc_init函數中完成。

    (2)整個初始化完成後去使用sd卡/iNand時,操作方法和mmc_init函數中初始化SD卡的操作一樣的方式。讀寫sd卡時也是通過總線向SD卡發送指令、讀取/寫入資料來完成的。

    (3)struct mmc結構體是關鍵。兩部分初始化之間用mmc結構體來連結的,初始化完了後對mmc卡的正常讀寫操作也是通過mmc結構體來連結的。

本文轉自 菜鳥養成記 51CTO部落格,原文連結:http://blog.51cto.com/11674570/1927550

繼續閱讀